using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Reflection;
using System.ComponentModel;

namespace SevenZip
{
    #region Extract class
    
    public class UnPacker
    {
        public void Unpack(string ArchiveName, string OutDir)
        {
            using (SevenZipFormat Format = new SevenZipFormat(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "7z.dll")))
            {
                KnownSevenZipFormat Formatnow = KnownSevenZipFormat.Compound;
                if(ArchiveName.EndsWith("zip", true, null))
                {
                    Formatnow = KnownSevenZipFormat.Zip;
                }
                if (ArchiveName.EndsWith("rar", true, null) || ArchiveName.EndsWith("r01", true, null))
                {
                    Formatnow = KnownSevenZipFormat.Rar;
                }
                if (ArchiveName.EndsWith("cab", true, null))
                {
                    Formatnow = KnownSevenZipFormat.Cab;
                }
                if (ArchiveName.EndsWith("Z", true, null))
                {
                    Formatnow = KnownSevenZipFormat.Z;
                }
                if (ArchiveName.EndsWith("rpm", true, null))
                {
                    Formatnow = KnownSevenZipFormat.Rpm;
                }
                if (ArchiveName.EndsWith("tar", true, null))
                {
                    Formatnow = KnownSevenZipFormat.Tar;
                }
                if (ArchiveName.EndsWith("7z", true, null))
                {
                    Formatnow = KnownSevenZipFormat.SevenZip;
                }
                //if (ArchiveName.EndsWith("gz", true, null) || ArchiveName.EndsWith("gzip", true, null))
                //{
                //    Formatnow = KnownSevenZipFormat.GZip;
                //}

                IInArchive Archive = Format.CreateInArchive(SevenZipFormat.GetClassIdFromKnownFormat(Formatnow));
                try
                {
                    using (InStreamWrapper ArchiveStream = new InStreamWrapper(File.OpenRead(ArchiveName)))
                    {
                        ulong CheckPos = 32 * 1024;
                        if (Archive.Open(ArchiveStream, ref CheckPos, null) != 0)
                        {
                            throw new FileLoadException("File not archive");
                        }
                        else
                        {
                            uint Count = Archive.GetNumberOfItems();
                            for (uint I = 0; I < Count; I++)
                            {
                                PropVariant Name = new PropVariant();
                                Archive.GetProperty(I, ItemPropId.kpidIsFolder, ref Name);
                                bool jajare = false;
                                try
                                {
                                    jajare = (bool)Name.GetObject();
                                }
                                catch (Exception)
                                { 
                                }
                                if (jajare == false)
                                {
                                    Archive.GetProperty(I, ItemPropId.kpidPath, ref Name);
                                    string FileName = (string)Name.GetObject();
                                    string folder = OutDir + "\\" + FileName;

                                    Archive.Extract(new uint[] { I }, 1, 0, new ArchiveCallback(I, folder));
                                }
                            }
                        }
                    }
                }
                finally
                {
                    Marshal.ReleaseComObject(Archive);
                }
            }

        }
    }
    #endregion

    #region Interface+stuff
    class ArchiveCallback : IArchiveExtractCallback
  {
    private uint FileNumber;
    private string FileName;
    private OutStreamWrapper FileStream;

    public ArchiveCallback(uint fileNumber, string fileName)
    {
      this.FileNumber = fileNumber;
      this.FileName = fileName;
    }

    #region IArchiveExtractCallback Members

    public void SetTotal(ulong total)
    {
    }

    public void SetCompleted(ref ulong completeValue)
    {
    }

    public int GetStream(uint index, out ISequentialOutStream outStream, AskMode askExtractMode)
    {
      if ((index == FileNumber) && (askExtractMode == AskMode.kExtract))
      {
        string FileDir = Path.GetDirectoryName(FileName);
        if (!string.IsNullOrEmpty(FileDir))
          Directory.CreateDirectory(FileDir);
        FileStream = new OutStreamWrapper(File.Create(FileName));

        outStream = FileStream;
      }
      else
        outStream = null;

      return 0;
    }

    public void PrepareOperation(AskMode askExtractMode)
    {
    }

    public void SetOperationResult(OperationResult resultEOperationResult)
    {
      FileStream.Dispose();
      Console.WriteLine(resultEOperationResult);
    }

    #endregion
  }
  #endregion
}
